package io.netty.example.study.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.example.study.client.codec.*;
import io.netty.example.study.client.codec.handler.dispatcher.OperationResultFuture;
import io.netty.example.study.client.codec.handler.dispatcher.RequestPendingCenter;
import io.netty.example.study.client.codec.handler.dispatcher.ResponseDispatcherHandler;
import io.netty.example.study.common.OperationResult;
import io.netty.example.study.common.RequestMessage;
import io.netty.example.study.common.order.OrderOperation;
import io.netty.example.study.util.IdUtil;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

import java.util.concurrent.ExecutionException;

/**
 * 基于 Guarded Suspension 模式，实现客户端获取响应结果的功能；
 */
public class ClientV2 {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.channel(NioSocketChannel.class);
        bootstrap.group(new NioEventLoopGroup());

        // 这是 Guarded Suspension 模式实现的关键，一个线程安全的 Map；
        final RequestPendingCenter requestPendingCenter = new RequestPendingCenter();

        bootstrap.handler(new ChannelInitializer<NioSocketChannel>() {
            @Override
            protected void initChannel(NioSocketChannel ch) throws Exception {
                // 需要注意顺序
                ChannelPipeline pipeline = ch.pipeline();
                pipeline.addLast(new OrderFrameDecoder());
                pipeline.addLast(new OrderFrameEncoder());
                pipeline.addLast(new OrderProtocolEncoder());
                pipeline.addLast(new OrderProtocolDecoder());

                // 需要添加在二次解码器 OrderProtocolDecoder 之后
                pipeline.addLast(new ResponseDispatcherHandler(requestPendingCenter));

                pipeline.addLast(new OperationToRequestMessageEncoder());
                pipeline.addLast(new LoggingHandler(LogLevel.INFO));
            }
        });

        ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 8090);
        channelFuture.sync();

        // 构造 streamId 和 operationResultFuture 的映射关系
        long streamId = IdUtil.nextId();
        RequestMessage requestMessage
                = new RequestMessage(streamId, new OrderOperation(1001, "tudou"));
        OperationResultFuture operationResultFuture = new OperationResultFuture();
        requestPendingCenter.add(streamId, operationResultFuture);

        // 发送消息，响应结果会在 ResponseDispatcherHandler 中被设置到 operationResultFuture 中，
        // 设置好了，operationResultFuture 会从 requestPendingCenter 中移除；
        channelFuture.channel().writeAndFlush(requestMessage);

        // 这个方法会阻塞，直到被 ResponseDispatcherHandler 设置了结果；
        OperationResult operationResult = operationResultFuture.get();
        System.out.println(operationResult);

        channelFuture.channel().closeFuture().get();
    }

}
